//! 类型转换（Conversion）
//!
//! Rust 中的类型转换是一个重要的概念。由于 Rust 是类型安全的语言，
//! 所以它不会自动进行类型转换或强制类型转换。需要显式地进行类型转换。
//! 本模块将演示几种常见的类型转换方式。
//!
//! ## 知识点总结
//!
//! | 知识点 | 说明 | 使用场景 |
//! |--------|------|---------|
//! | `as` 关键字 | 基本类型转换，如数值类型之间转换 | 简单类型转换，如 f32 转 u8 |
//! | `From`/`Into` trait | 安全类型转换，会消耗所有权 | 自定义类型转换，编译时确保安全 |
//! | `TryFrom`/`TryInto` trait | 可能失败的类型转换，返回 Result | 可能溢出或无效的转换 |
//! | `parse` 方法 | 字符串到数值类型的转换 | 解析用户输入或配置文件 |
//! | Newtype 模式 | 使用元组结构体或类型别名创建新类型 | 类型安全，添加实现，表达意图 |
//!
//! ## Newtype 模式
//!
//! Newtype 模式是 Rust 中一种重要的设计模式，它通过创建一个只包含
//! 单个字段的元组结构体或使用类型别名来创建新的类型。
//!
//! ### 优势
//! 1. 类型安全：防止不同类型之间的意外转换
//! 2. 实现 trait：可以为新类型实现 trait，而不能为原生类型实现
//! 3. 表达意图：类型名称可以更好地表达数据的含义和用途
//!
//! ### 示例
//! ```rust
//! // 使用类型别名的 Newtype 模式
//! type Kilometers = i32;
//!
//! // 使用元组结构体的 Newtype 模式
//! struct Meters(i32);
//! ```

/// 1. 使用 `as` 关键字进行基本类型转换
///
/// `as` 是 Rust 中最常见和最简单的类型转换方式，
/// 用于数值类型之间的转换。
#[allow(clippy::char_lit_as_u8)] //有更好的写法但这里是为了演示as的使用所以抑制clippy优化
pub fn as_keyword() {
    println!("\n=== 使用 as 关键字进行类型转换 ===");

    let decimal = 65.4321_f32;

    // 显式转换为整数类型
    let integer: u8 = decimal as u8;
    println!("{decimal} 转换为整数: {integer}");

    // 显式转换为有符号整数
    let signed_integer = decimal as i32;
    println!("{decimal} 转换为有符号整数: {signed_integer}");

    // 当转换可能导致数据丢失时，Rust 会进行截断或环绕
    let large_number = 1000_i16;
    let small_number = large_number as i8; // i8 范围是 -128 到 127
    println!("{large_number} 转换为 i8: {small_number}");

    // 字符和数字之间的转换
    let character = 'A' as u8;
    println!("字符 'A' 的 ASCII 值: {character}");

    let number = 66_u8;
    let char_from_number = number as char;
    println!("数字 {number} 对应的字符: {char_from_number}");
}

/// 2. 使用类型转换特性（From 和 Into）
///
/// `From` 和 `Into` 特性是 Rust 中更安全和更常用的类型转换方式。
/// 如果一个类型实现了 `From` 特性，那么它自动获得对应的 `Into` 特性。
pub fn from_into_traits() {
    println!("\n=== 使用 From 和 Into 特性进行类型转换 ===");

    // String::from 和 Into<String>
    let my_str = "hello";
    let string1 = String::from(my_str);
    let string2: String = my_str.into();

    println!("从 &str 转换为 String: '{string1}' 和 '{string2}'");

    // 数值类型之间的安全转换
    let num_i32: i32 = 5;
    let num_i64: i64 = num_i32.into(); // i32 可以安全地转换为 i64
    println!("i32 {num_i32} 转换为 i64: {num_i64}");

    // 自定义类型转换示例
    #[derive(Debug, Clone)]
    struct MyInt(i32);

    #[derive(Debug)]
    struct YourInt(i32);

    // 实现 From 特性，允许从 MyInt 转换为 YourInt
    impl From<MyInt> for YourInt {
        fn from(item: MyInt) -> Self {
            YourInt(item.0)
        }
    }

    let my_int = MyInt(42);
    let your_int: YourInt = my_int.clone().into();
    println!("自定义类型转换: {my_int:?} -> {your_int:?}");
}

/// 3. 使用 TryFrom 和 TryInto 进行可能失败的转换
///
/// 当转换可能失败时，应该使用 `TryFrom` 和 `TryInto` 特性，
/// 它们返回 `Result` 类型而不是直接返回值。
pub fn try_from_into_traits() {
    println!("\n=== 使用 TryFrom 和 TryInto 进行可能失败的转换 ===");

    use std::convert::TryFrom;
    use std::convert::TryInto;

    // 尝试将大数转换为小数类型
    let big_number = 1000i32;
    let small_number = i8::try_from(big_number);

    match small_number {
        Ok(value) => println!("成功转换: {value}"),
        Err(e) => println!("转换失败: {e}"),
    }

    // 在范围内转换
    let small_number = 50i32;
    let converted: Result<i8, _> = small_number.try_into();

    match converted {
        Ok(value) => println!("成功转换: {value}"),
        Err(e) => println!("转换失败: {e}"),
    }
}

/// 4. 解析字符串为数值类型
///
/// 字符串到数值的转换是一种常见的操作，通常使用 `parse` 方法。
pub fn parsing_strings() {
    println!("\n=== 解析字符串为数值类型 ===");

    let parsed: i32 = "5".parse().unwrap();
    println!("字符串 '5' 解析为 i32: {parsed}");

    let parsed_float: f64 = "3.14159".parse().unwrap();
    println!("字符串 '3.14159' 解析为 f64: {parsed_float}");

    // 错误处理示例
    let invalid_parse = "abc".parse::<i32>();
    match invalid_parse {
        Ok(value) => println!("解析成功: {value}"),
        Err(e) => println!("解析失败: {e:?}"),
    }

    // 使用 turbofish 语法 (::<>)
    let another_parse = "123".parse::<i32>().unwrap();
    println!("使用 turbofish 语法解析: {another_parse}");
}

/// 5. 使用指针转换
///
/// 在处理原始指针和引用时，需要进行指针类型之间的转换。
pub fn pointer_conversion() {
    println!("\n=== 指针转换示例 ===");

    let array = [1, 2, 3];
    let ptr = array.as_ptr();

    // 将指针转换为 usize
    let address = ptr as usize;
    println!("数组首元素的地址: 0x{:x}", address);

    // 从 usize 转换回指针（不安全操作）
    let _ptr_back = address as *const i32;

    // 引用到原始指针的转换
    let x = 42;
    let raw_ptr = &x as *const i32;
    println!("变量 x 的地址: {:p}", raw_ptr);
}

/// 6. Newtype 模式示例
///
/// 展示如何使用 Newtype 模式创建类型安全的包装类型
pub fn newtype_pattern() {
    println!("\n=== Newtype 模式示例 ===");

    // 使用类型别名的 Newtype 模式
    type Kilometers = i32;
    type Miles = i32;

    // 虽然底层类型相同，但编译器将它们视为不同类型
    let km: Kilometers = 100;
    let miles: Miles = 50;

    // 不能直接比较或运算（需要显式转换）
    // println!("{}", km == miles); // 编译错误！
    println!("距离: {km} 公里");
    println!("距离: {miles} 英里");

    // 使用元组结构体的 Newtype 模式（更严格的类型安全）
    #[derive(Debug, Clone, Copy, PartialEq)]
    struct Celsius(f64);

    #[derive(Debug, Clone, Copy, PartialEq)]
    struct Fahrenheit(f64);

    // 为 Newtype 实现方法
    impl Celsius {
        fn new(value: f64) -> Self {
            Celsius(value)
        }

        fn to_fahrenheit(self) -> Fahrenheit {
            Fahrenheit(self.0 * 9.0 / 5.0 + 32.0)
        }

        fn value(&self) -> f64 {
            self.0
        }
    }

    impl Fahrenheit {
        fn new(value: f64) -> Self {
            Fahrenheit(value)
        }

        fn to_celsius(self) -> Celsius {
            Celsius((self.0 - 32.0) * 5.0 / 9.0)
        }

        fn value(&self) -> f64 {
            self.0
        }
    }

    // 使用 Newtype
    let celsius_temp = Celsius::new(25.0);
    let fahrenheit_temp = celsius_temp.to_fahrenheit();

    println!("摄氏温度: {celsius_temp:?}");
    println!("华氏温度: {fahrenheit_temp:?}");

    // 不能混淆使用
    // let invalid_temp: Fahrenheit = Celsius::new(25.0); // 编译错误！
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_as_keyword() {
        let decimal = 65.4321_f32;
        let integer: u8 = decimal as u8;
        assert_eq!(integer, 65);

        let large_number = 1000_i16;
        let small_number = large_number as i8;
        assert_eq!(small_number, -24); // 由于环绕，1000 超出了 i8 的范围
    }

    #[test]
    fn test_from_into_traits() {
        let my_str = "hello";
        let string1 = String::from(my_str);
        let string2: String = my_str.into();
        assert_eq!(string1, "hello");
        assert_eq!(string2, "hello");

        // 测试自定义类型的转换
        #[derive(Debug, Clone, PartialEq)]
        struct MyInt(i32);

        #[derive(Debug, PartialEq)]
        struct YourInt(i32);

        impl From<MyInt> for YourInt {
            fn from(item: MyInt) -> Self {
                YourInt(item.0)
            }
        }

        let my_int = MyInt(42);
        let your_int: YourInt = my_int.clone().into();
        assert_eq!(your_int, YourInt(42));
    }

    #[test]
    fn test_try_from_into_traits() {
        use std::convert::TryFrom;

        // 测试超出范围的转换应该失败
        let big_number = 1000i32;
        let small_number = i8::try_from(big_number);
        assert!(small_number.is_err());

        // 测试在范围内的转换应该成功
        let small_number = 50i32;
        let converted: Result<i8, _> = small_number.try_into();
        assert!(converted.is_ok());
        assert_eq!(converted.unwrap(), 50);
    }

    #[test]
    fn test_parsing_strings() {
        let parsed: i32 = "5".parse().unwrap();
        assert_eq!(parsed, 5);

        let parsed_float: f64 = "3.14159".parse().unwrap();
        assert_eq!(parsed_float, 3.14159);

        // 测试无效解析应该失败
        let invalid_parse = "abc".parse::<i32>();
        assert!(invalid_parse.is_err());
    }

    #[test]
    fn test_newtype_pattern() {
        // 测试类型别名 Newtype
        type Kilometers = i32;
        type Miles = i32;

        let km: Kilometers = 100;
        let miles: Miles = 50;

        assert_eq!(km, 100);
        assert_eq!(miles, 50);

        // 测试元组结构体 Newtype
        #[derive(Debug, Clone, Copy, PartialEq)]
        struct Celsius(f64);

        impl Celsius {
            fn new(value: f64) -> Self {
                Celsius(value)
            }

            fn value(&self) -> f64 {
                self.0
            }
        }

        let celsius = Celsius::new(25.0);
        assert_eq!(celsius.value(), 25.0);
    }
}
